package com.central.modules.sys.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.central.modules.sys.dao.SysMenuDao;
import com.central.modules.sys.entity.SysMenuEntity;
import com.central.modules.sys.model.AddSysMenuRequest;
import com.central.modules.sys.service.SysMenuService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.validation.constraints.NotNull;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuDao, SysMenuEntity> implements SysMenuService {
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addMenu(AddSysMenuRequest request) {
        SysMenuEntity sysMenu = new SysMenuEntity();
        BeanUtils.copyProperties(request, sysMenu);
        this.save(sysMenu);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateMenu(Long id, AddSysMenuRequest request) {
        SysMenuEntity sysMenu = new SysMenuEntity();
        BeanUtils.copyProperties(request, sysMenu);
        sysMenu.setId(id);
        this.updateById(sysMenu);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteMenu(Long id) {
        // 查询父节点为当前节点的节点
        List<SysMenuEntity> menuList = this.list(Wrappers.<SysMenuEntity>query().lambda().eq(SysMenuEntity::getParentId, id));
        if (CollUtil.isEmpty(menuList)) {
            // 删除当前菜单及其子菜单
            return this.removeById(id);
        }
        return false;
    }

    @Override
    public List<SysMenuEntity> findAll() {
        return this.list(
                new QueryWrapper<SysMenuEntity>().lambda().orderByAsc(SysMenuEntity::getSortOrder)
        );
    }

    @Override
    public List<String> getPermissionsList() {
        QueryWrapper<SysMenuEntity> queryWrapper = new QueryWrapper<SysMenuEntity>();
        queryWrapper.lambda().select(SysMenuEntity::getPermissions).isNotNull(SysMenuEntity::getPermissions);
        return this.list(queryWrapper).stream().map(SysMenuEntity::getPermissions).collect(Collectors.toList());
    }

    @Override
    public List<String> getUserPermissionsList(Long userId) {
        return this.baseMapper.getUserPermissionsList(userId);
    }

    @Override
    public List<SysMenuEntity> findByIdsAndType(List<Long> ids, Integer type) {
        if (CollectionUtils.isEmpty(ids)) {
            return Collections.EMPTY_LIST;
        }
        return this.list(
                new QueryWrapper<SysMenuEntity>().lambda().in(SysMenuEntity::getId, ids).eq(SysMenuEntity::getType, type).orderByAsc(SysMenuEntity::getSortOrder)
        );
    }

    @Override
    public List<Tree<Long>> treeMenu(Long parentId, String menuName, String type) {
        Long parent = parentId == null ? 0 : parentId;

        List<TreeNode<Long>> collect = baseMapper
                .selectList(Wrappers.<SysMenuEntity>lambdaQuery()
                        .like(StrUtil.isNotBlank(menuName), SysMenuEntity::getName, menuName)
                        .eq(StrUtil.isNotBlank(type), SysMenuEntity::getType, type)
                        .orderByAsc(SysMenuEntity::getSortOrder))
                .stream()
                .map(getNodeFunction())
                .collect(Collectors.toList());

        // 模糊查询 不组装树结构 直接返回 表格方便编辑
        if (StrUtil.isNotBlank(menuName)) {
            return collect.stream().map(node -> {
                Tree<Long> tree = new Tree<>();
                tree.putAll(node.getExtra());
                BeanUtils.copyProperties(node, tree);
                return tree;
            }).collect(Collectors.toList());
        }
//        TreeNodeConfig config = new TreeNodeConfig();
//        //id
//        config.setIdKey("id");
//        //父id
//        config.setParentIdKey("pid");
//        //名称
//        config.setNameKey("name");
//        //最大递归深度
//        config.setDeep(3);
//        //孩子节点
//        config.setChildrenKey("childrenList");
//        //排序字段
//        config.setWeightKey("sortOrder");
        return TreeUtil.build(collect, parent);
    }

    @NotNull
    private Function<SysMenuEntity, TreeNode<Long>> getNodeFunction() {
        return menu -> {
            TreeNode<Long> node = new TreeNode<>();
            node.setId(menu.getId());
            node.setName(menu.getName());
            node.setParentId(menu.getParentId());
            node.setWeight(menu.getSortOrder());
            // 扩展属性
            Map<String, Object> extra = new HashMap<>();
            extra.put("path", menu.getPath());
            extra.put("type", menu.getType());
            extra.put("permissions", menu.getPermissions());
            extra.put("sortOrder", menu.getSortOrder());
            extra.put("pathMethod", menu.getPathMethod());
            extra.put("visible", menu.getVisible());
            extra.put("keepAlive", menu.getKeepAlive());
            extra.put("embedded", menu.getEmbedded());

            // 适配 vue3
            Map<String, Object> meta = new HashMap<>();
            meta.put("title", menu.getName());
            meta.put("isLink", menu.getPath() != null && menu.getPath().startsWith("http") ? menu.getPath() : "");
            meta.put("isHide", menu.getVisible());
            meta.put("isKeepAlive", menu.getKeepAlive());
            meta.put("isAffix", false);
            meta.put("isIframe", menu.getEmbedded());
            meta.put("icon", menu.getIcon());
            extra.put("meta", meta);
            node.setExtra(extra);
            return node;
        };
    }
}
